#!/usr/bin/env python2.5
import sys
import re
import os.path
import os

argc = len(sys.argv)

report = None

# TODO: replace this hardcoded value with program argument
output_dir = "html-report"

# read report from file if set or from stdin
if 2 == argc:
    # get report filename
    report_file = sys.argv[1]

    # try to open
    try:
        report = open(report_file)
    except:
        print >>sys.stderr, "Unable to open file `%s'" % report_file
        sys.exit(1)
else:
    # open stdin
    report = sys.stdin

if not os.path.exists(output_dir):
    os.mkdir(output_dir)

hdr_re = re.compile("^(Name\s+)(Stmts)(\s+Exec)(\s+Cover)(\s+Missing)$")
delim_re = re.compile("^-+$")

line = report.readline()
mo = hdr_re.search(line)
if mo is None:
    print >>sys.stderr, "Invalid report header format"
    sys.exit(1)

gr = [len(x) for x in mo.groups()]
gr = gr[0:-1] # remove last element

# build line matching re
res_re_str = "^"
for l in gr:
    res_re_str += "(.{%i})" % l
res_re_str += "(.+)$"
res_re = re.compile(res_re_str)

line = report.readline()
mo = delim_re.match(line)
if mo is None:
    print >>sys.stderr, "Invalid report format: missing delimiter"
    sys.exit(1)

files_index = []

report_html_template = """<html><head>
<style type="text/css">
.preserve-spaces {
    white-space: pre;
    font-family: monospace;
}
.low-cov {background-color: #ffbfbf;}
.mid-cov {background-color: #fdffb9;}
.hi-cov {background-color: #b8ffb4;}
.missing {
    background-color: #ffb4b4;
}
</style>
</head>
<body>
%(body)s
</body>
</html>"""

def expand_missing(missing):
    res = []
    if "" == missing:
        return res

    #print missing
    groups = missing.split(", ")
    for g in groups:
        #print g
        s = g.split("-")
        if len(s) == 1:
            # i.e. there is just one number
            #print s
            res.append(int(s[0]))
        else:
            start, stop = [int(x) for x in s]
            res += range(start, stop+1)

    return res

for line in report:
    mo = delim_re.match(line)
    if not mo is None:
        break

    mo = res_re.match(line)
    if mo is None:
        print >>sys.stderr, "Invalid line format"
        sys.exit(1)

    filename, statements, execs, coverage, missing = [x.strip() for x in mo.groups()]
    filename += ".py"
    missing_lines = expand_missing(missing)
    metrics = {
        'statements': statements,
        'execs': execs,
        'coverage': coverage,
        'missing': missing       
        }

    # generate fancy report for each file
    report_filename = filename.replace("/", "_")+".html" 
    #report_filename = os.path.join(output_dir, report_filename)

    try:
        src = open(filename)
    except:
        print >>sys.stderr, "Unable to open source file `%s'" % filename
        sys.exit(1)

    src_line_num = 1
    
    report = '<table border="0">'
    for src_line in src:
        src_line = src_line.rstrip()
        src_line = src_line.replace("<", "&lt;").replace("&", "&amp;")
        cls = "regular"
        if src_line_num in missing_lines:
            cls += " missing"
        # check that line is in the missing table
        report += '<tr class="%s"><td align="right">%i</td><td class="preserve-spaces">%s</td></tr>\n' % (cls, src_line_num, src_line)
        src_line_num += 1
    report += "</table>"

    try:
        out = open(os.path.join(output_dir, report_filename), "w")
    except:
        print >>sys.stderr, "Unable to open file `%s' for writing" % report_filename
        sys.exit(1)
    out.write(report_html_template % {'body': report})
    out.close()
    src.close()

    files_index.append( (report_filename, filename, metrics) )


report_index = ""
report_index += '<table border="0">'
report_index += '''<tr><td><b>file</b></td> <td><b>statements</b></td> <td><b>execs</b></td> 
    <td><b>coverage</b></td> <td><b>missing lines</b></td> </tr>'''
for report_filename, filename, metrics in files_index:
    coverage = 0
    try:
        coverage = int(metrics['coverage'][:-1])
    except:
        pass
    
    cov_style = "low-cov";
    if coverage >= 30 and coverage < 70:
        cov_style = "mid-cov"
    elif coverage >= 70:
        cov_style = "hi-cov"
    
    report_index += '''<tr class="%(cov_style)s"><td style="white-space:nowrap;"><a href="%(report_filename)s">%(filename)s</a></td>
        <td align="right">%(statements)s</td>
        <td align="right">%(execs)s</td>
        <td align="right">%(coverage)s</td>
        <td>%(missing)s</td></tr>''' % {
        'report_filename': report_filename,
        'filename': filename,
        'statements': metrics['statements'],
        'execs': metrics['execs'],
        'coverage': metrics['coverage'],
        'missing': metrics['missing'],
        'cov_style': cov_style
        }

report_index += "</table>"

report_index = report_html_template % {
    'body': report_index
    }

index_filename = os.path.join(output_dir, "index.html")
try:
    index = open(index_filename, "w")
except:
    print >>sys.stderr, "Unable to open file `%s' for writing" % index_filename
    sys.exit(1)
    
index.write(report_index)
index.close()
